1 Preparations for analysis

Loading packages to simulate and manipulate data.

library(MASS)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ───────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.3     ✓ purrr   0.3.4
✓ tibble  3.1.1     ✓ dplyr   1.0.6
✓ tidyr   1.1.3     ✓ stringr 1.4.0
✓ readr   1.4.0     ✓ forcats 0.5.1
── Conflicts ──────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
x dplyr::select() masks MASS::select()

2 Simulate data

Data generation was performed according to the following conditions:

  • Correlations: 0.12, 0.20, 0.31, 0.50
  • Sample sizes: 50, 100, 250, 500, 1000
  • Number of replications: 1000

In this way, 20 dataframes are generated with different amounts of data within each of them, which will have 1,000 replications. In total, 20,000 dataframes with observations for analysis.

2.1 Generate matrices and observations

Create the variables that indicate the conditions

set.seed(2020) 
r <- c(0.12, 0.20, 0.31, 0.50) ## Correlaciones 
n <- c(50, 100, 250, 500, 1000) ## Tamaño de muestra
replic <- 1000
# Generar las matrices de correlación
sigma <- list()
for (i in seq_along(r)) { 
  sigma[[i]] <- matrix(data = c(1, rep(r[i], 2), 1),
                       nrow = 2,
                       ncol = 2)
}


# Generar los datos de correlación
df_cor <- list()
for (i in seq_along(sigma)) {
  df_cor[[i]] <- list()
  for (j in seq_along(n)) {
    df_cor[[i]][[j]] <- list()
    for (k in 1:replic) {
      df_cor[[i]][[j]][[k]] <- mvrnorm(n     = n[j],
                                       mu    = rep(0, 2),
                                       Sigma = sigma[[i]]) %>% 
        as_tibble()
    }
  }
}
The `x` argument of `as_tibble.matrix()` must have unique column names if `.name_repair` is omitted as of tibble 2.0.0.
Using compatibility `.name_repair`.

2.2 Format the data as dataframe / tibbles

We will assemble the list object in such a way that we can identify by columns the correlation, sample size and replicate number of each observation.

2.3 Add outliers

Five percent of the data in each data frame will be randomly replaced by outlier correlations different from the one generated. For example, in the case of a dataframe with a correlation of 0.12 and a sample size of 50, 3 pairs of correlations will be randomly replaced with 3 pairs of correlations generated with correlations of 0.20, 0.31 and 0.50.

# Add the number of outliers to be added and their locations Outliers at 5%.
df_work <- df_nest %>% 
  rowwise() %>% 
  mutate(
    ratio_outlier = map_dbl(n,
                        ~ ceiling(0.05*n)),
    posici_rep_m3 = map2(n, ratio_outlier,
                         ~ sample(1:.x, .y)),
    posici_rep_m6 = map2(n, ratio_outlier,
                         ~ sample(1:.x, .y)),
    posici_rep_m3v1 = map2(n, ratio_outlier,
                          ~ sample(1:.x, .y)),
    posici_rep_m3v2 = map2(n, ratio_outlier,
                          ~ sample(1:.x, .y)),
    posici_rep_m3v3 = map2(n, ratio_outlier,
                          ~ sample(1:.x, .y)),
    posici_rep_m6v1 = map2(n, ratio_outlier,
                           ~ sample(1:.x, .y)),
    posici_rep_m6v2 = map2(n, ratio_outlier,
                           ~ sample(1:.x, .y)),
    posici_rep_m6v3 = map2(n, ratio_outlier,
                           ~ sample(1:.x, .y))
  )

# Add correlations that were not considered
df_work <- df_work %>% 
  mutate(
    correla_a = r[which(correlacion != r)[1]],
    correla_b = r[which(correlacion != r)[2]],
    correla_c = r[which(correlacion != r)[3]]
  )

On the correlations identified to be generated, the data matrix necessary for the multivariate simulation is created as an outlier.

df_work <- df_work %>% 
  mutate(
    matrix = map(correlacion,
                 ~ matrix(data = rep(c(1, rep(.x, 2)), 2), 
                          nrow = 2,
                          ncol = 2)),
    matrix_a = map(correla_a,
                   ~ matrix(data = rep(c(1, rep(.x, 2)), 2), 
                            nrow = 2,
                            ncol = 2)),
    matrix_b = map(correla_b,
                   ~ matrix(data = rep(c(1, rep(.x, 2)), 2), 
                            nrow = 2,
                            ncol = 2)),
    matrix_c = map(correla_c,
                   ~ matrix(data = rep(c(1, rep(.x, 2)), 2), 
                            nrow = 2,
                            ncol = 2))
  ) %>% 
  ungroup()

Aggregate outliers are of 2 types: they vary only by the mean and they vary by the mean and its matrix:

  • outlier_m3: Varies by an mean of 3
  • outlier_m6: Varies by an mean of 6
  • outlier_m3v1: Varies by an mean of 3 and matrix a
  • outlier_m3v2: Varies by an mean of 3 and matrix b
  • outlier_m3v3: Varies by an mean of 3 and matrix c
  • outlier_m6v1: Varies by an mean of 6 and matrix a
  • outlier_m6v2: Varies by an mean of 6 and matrix b
  • outlier_m6v3: Varies by an mean of 6 and matrix c
set.seed(2019) 

df_work <- df_work %>% 
  mutate(
    outlier_m3 = map2(ratio_outlier, matrix, 
                      ~ mvrnorm(n     = .x,
                                mu    = rep(3, 2),
                                Sigma = .y) %>% 
                        as_tibble()),
    outlier_m6 = map2(ratio_outlier, matrix,
                      ~ mvrnorm(n     = .x,
                                mu    = rep(6, 2),
                                Sigma = .y) %>% 
                        as_tibble()),
    outlier_m3v1 = map2(ratio_outlier, matrix_a, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(3, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m3v2 = map2(ratio_outlier, matrix_b, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(3, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m3v3 = map2(ratio_outlier, matrix_c, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(3, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m6v1 = map2(ratio_outlier, matrix_a, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(6, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m6v2 = map2(ratio_outlier, matrix_b, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(6, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m6v3 = map2(ratio_outlier, matrix_c, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(6, 2),
                                  Sigma = .y) %>% 
                          as_tibble())
  )

These new simulated outlier correlations will be inserted into the initially calculated random positions in each dataframe.

df_work <- df_work %>% 
  mutate(
    data_out_m3 = pmap(list(data, posici_rep_m3, outlier_m3),
                       ~ ..1 %>% 
                         slice(- ..2) %>% 
                         bind_rows(..3)),
    data_out_m6 = pmap(list(data, posici_rep_m6, outlier_m6),
                       ~ ..1 %>% 
                         slice(- ..2) %>% 
                         bind_rows(..3)),
    data_out_m3v1 = pmap(list(data, posici_rep_m3v1, outlier_m3v1),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m3v2 = pmap(list(data, posici_rep_m3v2, outlier_m3v2),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m3v3 = pmap(list(data, posici_rep_m3v3, outlier_m3v3),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m6v1 = pmap(list(data, posici_rep_m6v1, outlier_m6v1),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m6v2 = pmap(list(data, posici_rep_m6v2, outlier_m6v2),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m6v3 = pmap(list(data, posici_rep_m6v3, outlier_m6v3),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3))
  )

Additionally, new dataframes with the same correlation conditions, sample size and number of replications with non-normal data distributions are generated using the algorithm of Vale and Maurelli (1983).

Non-normality conditions were generated on the basis of the work of Sheng & Sheng (2012):

  • skewness = 0.00, kurtosis = − 1.385 (symmetric platykurtic distribution);
  • skewness = 0.00, kurtosis = 25 (symmetric leptokurtic distribution);
  • skewness = 0.96, kurtosis = 0.13 (non-symmetric distribution);
  • skewness = 0.48, kurtosis = − 0.92 (non-symmetric platykurtic distribution);
  • skewness = 2.50, kurtosis = 25 (non-symmetric leptokurtic distribution).
set.seed(2021) 
library(semTools)

df_work <- df_work %>% 
  mutate(
    data_nonorm1 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = c(0),
                                     kurtosis = c(-1.385)) %>% # symmetric platykurtic distribution
                          as_tibble()),
    data_nonorm2 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = 0,
                                     kurtosis = 25) %>% # symmetric leptokurtic distribution 
                          as_tibble()),
    data_nonorm3 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = 0.96,
                                     kurtosis = 0.13) %>% # non-symmetric distribution
                          as_tibble()),
    data_nonorm4 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = 0.48,
                                     kurtosis = -0.92) %>% # non-symmetric platykurtic distribution
                          as_tibble()),
    data_nonorm5 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = 2.5,
                                     kurtosis = 25) %>% # non-symmetric leptokurtic distribution
                          as_tibble())
  )

Finally, the variables that will no longer be used are eliminated.

df_work <- df_work %>% 
  select(-c(ratio_outlier:outlier_m6v3))

3 Calculation of correlations

3.1 Format tidy data

df_work_tidy <- df_work %>% 
  pivot_longer(
    cols = data:data_nonorm5,
    names_to = "Tipo_Sim",
    values_to = "Data"
  )

3.2 Correlations

library(WRS2)
df_work_tidy <- df_work_tidy %>% 
  mutate(
    cort_pears = map(Data,
                     ~ cor.test(.x$V1, .x$V2,
                                method = "pearson")),
    cort_spear = map(Data,
                     ~ cor.test(.x$V1, .x$V2,
                                method = "spearman")),
    cort_winso = map(Data,
                     ~ wincor(.x$V1, .x$V2,
                              tr = 0.2))
  )

3.3 Obtain the coefficients

df_work_tidy <- df_work_tidy %>% 
  mutate(
    coef_pears = map_dbl(cort_pears,
                         ~ .x$estimate[1]),
    coef_spear = map_dbl(cort_spear,
                         ~ .x$estimate[1]),
    coef_winso = map_dbl(cort_winso,
                         ~ .x$cor[1])
  )

df_work_tidy_simp <- df_work_tidy %>% 
  select(-c(Data:cort_winso))

4 Evaluate simulation

4.1 Calculate RMSEA and Bias

df_work_tidy_simp <- df_work_tidy_simp %>% 
  rowwise() %>% 
  mutate(
    dif_pears = (coef_pears - correlacion)/correlacion,
    dif_spear = (coef_spear - correlacion)/correlacion,
    dif_winso = (coef_winso - correlacion)/correlacion
  ) %>% 
  ungroup()

df_work_tidy_simp <- df_work_tidy_simp %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  summarise(
    rmsea_pears = sqrt(sum(dif_pears^2)/1000),
    sesgo_pears = (sum(dif_pears)/1000),
    rmsea_spear = sqrt(sum(dif_spear^2)/1000),
    sesgo_spear = (sum(dif_spear)/1000),
    rmsea_winso = sqrt(sum(dif_winso^2)/1000),
    sesgo_winso = (sum(dif_winso)/1000)
  ) %>% 
  ungroup()
`summarise()` has grouped output by 'correlacion', 'n'. You can override using the `.groups` argument.
df_work_tidy_simp

4.2 Recode simulation types

df_work_tidy_simp <- df_work_tidy_simp %>% 
  mutate(
    Tipo_Sim = fct_recode(Tipo_Sim,
                          "MVN" = "data",
                          "OL M3" = "data_out_m3",
                          "OL M6" = "data_out_m6",
                          "OL M3 V1" = "data_out_m3v1",
                          "OL M3 V2" = "data_out_m3v2",
                          "OL M3 V3" = "data_out_m3v3",
                          "OL M6 V1" = "data_out_m6v1",
                          "OL M6 V2" = "data_out_m6v2",
                          "OL M6 V3" = "data_out_m6v3",
                          "No-MVN A" = "data_nonorm1",
                          "No-MVN B" = "data_nonorm2",
                          "No-MVN C" = "data_nonorm3",
                          "No-MVN D" = "data_nonorm4",
                          "No-MVN E" = "data_nonorm5"),
    Tipo_Sim = fct_relevel(Tipo_Sim,
                           "MVN", "OL M3", "OL M6", "OL M3 V1", 
                           "OL M3 V2", "OL M3 V3", "OL M6 V1",
                           "OL M6 V2", "OL M6 V3")
  ) %>% 
  arrange(correlacion, n, Tipo_Sim)

4.3 Complete table about RMSEA and Bias

df_work_tidy_simp_A <- df_work_tidy_simp %>% 
  relocate(contains("sesgo"), .after = "rmsea_winso")

df_work_tidy_simp_A

4.4 Recalculation of RMSEA and Bias grouping conditions

df_work_tidy_simp_B <- df_work_tidy_simp %>%
  mutate(
    Tipo_Sim = fct_collapse(Tipo_Sim,
                            "MVN" = "MVN",
                            "MVN OL M3" = "OL M3",
                            "MVN OL M6" = "OL M6",
                            "MVN OL M3V" = c("OL M3 V1", "OL M3 V2", "OL M3 V3"),
                            "MVN OL M6V" = c("OL M6 V1", "OL M6 V2", "OL M6 V3"),
                            "No-MVN" = c("No-MVN A", "No-MVN C", "No-MVN D"),
                            "No-MVN ks+" = c("No-MVN B", "No-MVN E")
    )
  ) %>% 
  relocate(contains("sesgo"), .after = "rmsea_winso")

df_work_tidy_simp_B <- df_work_tidy_simp_B %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  summarise(
    across(everything(), mean)
  ) %>% 
  ungroup()
`summarise()` has grouped output by 'correlacion', 'n'. You can override using the `.groups` argument.
df_work_tidy_simp_B

4.5 Format tidy data

df_work_tidy_simp <- df_work_tidy_simp %>% 
  pivot_longer(
    cols = rmsea_pears:sesgo_winso,
    names_to = "Ajuste",
    values_to = "Valor"
  ) %>% 
  mutate(
    Ajuste = fct_recode(Ajuste,
                        "RMSE Pearson" = "rmsea_pears",
                        "RMSE Spearman" = "rmsea_spear",
                        "RMSE Winsorized" = "rmsea_winso",
                        "Sesgo Pearson" = "sesgo_pears",
                        "Sesgo Spearman" = "sesgo_spear",
                        "Sesgo Winsorized" = "sesgo_winso")
  )

4.6 Plots

plot_assess_A <- df_work_tidy_simp %>%
  mutate(
    correlacion = factor(correlacion, 
                         labels = c("0.12", "0.20",
                                    "0.31", "0.50"))
  ) %>% 
  filter(correlacion != "0.50") %>% 
  ggplot(aes(x = Tipo_Sim, y = Valor,
             # colour = Ajuste,
             shape = Ajuste,
             linetype = Ajuste,
             group = Ajuste)) +
  geom_point(color = "#3a3a3a", size = 2) +
  geom_path(color = "#3a3a3a") +
  scale_y_continuous(limits = c(-0.5, 5.5),
                     breaks = seq(-0.5, 5.5, 1)) +
  labs(title = "",
       x = "Condiciones de Simulación",
       y = "") +
  # scale_x_discrete(guide = guide_axis(n.dodge = 2)) +
  facet_grid(correlacion ~ n) +
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5,
                              size = 12,
                              face = "bold"),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 9,
      face="plain",
      colour="black"),
    axis.text.x = element_text(angle = 90),
    axis.title.x = element_text(
      size = 11,
      margin = margin(t = 7, r = 0, b = 0, l = 0)
    ),
    strip.text = element_text(
      size = 11
    ),
    legend.title = element_blank(),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=10),
    panel.spacing = unit(0.8, "lines")
  ) 

plot_assess_B <- df_work_tidy_simp %>%
  mutate(
    correlacion = factor(correlacion, 
                         labels = c("0.12", "0.20",
                                    "0.31", "0.50"))
  ) %>% 
  filter(correlacion != "0.50") %>% 
  ggplot(aes(x = Tipo_Sim, y = Valor,
             # colour = Ajuste,
             shape = Ajuste,
             linetype = Ajuste,
             group = Ajuste)) +
  geom_point(color = "#3a3a3a", size = 2) +
  geom_path(color = "#3a3a3a") +
  scale_y_continuous(limits = c(-0.5, 5.5),
                     breaks = seq(-0.5, 5.5, 1)) +
  labs(title = "",
       x = "Condiciones de Simulación",
       y = "") +
  # scale_x_discrete(guide = guide_axis(n.dodge = 2)) +
  facet_grid(n ~ correlacion) +
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5,
                              size = 12,
                              face = "bold"),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 9,
      face="plain",
      colour="black"),
    axis.text.x = element_text(angle = 90),
    axis.title.x = element_text(
      size = 11,
      margin = margin(t = 7, r = 0, b = 0, l = 0)
    ),
    strip.text = element_text(
      size = 11
    ),
    legend.title = element_blank(),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=10),
    panel.spacing = unit(0.8, "lines")
  ) 

5 Evaluate normality

5.1 Calculation of kurtosis and skewness for each variable

5.2 Calculation evaluating multivariate normality

5.2.1 Settings multicore

library(multidplyr)

if (Sys.getenv("RSTUDIO") == "1" && !nzchar(Sys.getenv("RSTUDIO_TERM")) && 
    (Sys.info()["sysname"] == "Darwin" || Sys.info()["sysname"] == "Linux") && 
    getRversion() >= "4.0.0") {
  parallel:::setDefaultClusterOptions(setup_strategy = "sequential")
}

cluster <- new_cluster(parallel::detectCores())

5.2.2 Evaluation

df_work_tidy_evaluate <- df_work_tidy_evaluate %>% 
  partition(cluster) %>% 
  mutate(
    Normal_multi_r = purrr::map_chr(Data,
                             ~ MVN::mvn(.x)$multivariateNormality$Result[3])
  ) %>% 
  collect()

5.2.3 Categorize by kurtosis and skewness

df_work_tidy_evaluate <- df_work_tidy_evaluate %>% 
  mutate(
    norm_uni = ifelse(kurtosis_v1 >= - 1.5 & kurtosis_v1 <= 1.5 &
                        skewness_v1 >= - 1.5 & skewness_v1 <= 1.5 &
                        kurtosis_v2 >= - 1.5 & kurtosis_v2 <= 1.5 &
                        skewness_v2 >= - 1.5 & skewness_v2 <= 1.5, 
                      "Si", "No")
  )

5.3 Format tidy data

df_work_tidy_evaluate <- df_work_tidy_evaluate %>%
  mutate(
    Tipo_Sim = fct_recode(Tipo_Sim,
                          "MVN" = "data",
                          "OL M3" = "data_out_m3",
                          "OL M6" = "data_out_m6",
                          "OL M3 V1" = "data_out_m3v1",
                          "OL M3 V2" = "data_out_m3v2",
                          "OL M3 V3" = "data_out_m3v3",
                          "OL M6 V1" = "data_out_m6v1",
                          "OL M6 V2" = "data_out_m6v2",
                          "OL M6 V3" = "data_out_m6v3",
                          "No-MVN A" = "data_nonorm1",
                          "No-MVN B" = "data_nonorm2",
                          "No-MVN C" = "data_nonorm3",
                          "No-MVN D" = "data_nonorm4",
                          "No-MVN E" = "data_nonorm5"),
    Tipo_Sim = fct_relevel(Tipo_Sim,
                           "MVN", "OL M3", "OL M6", "OL M3 V1", 
                           "OL M3 V2", "OL M3 V3", "OL M6 V1",
                           "OL M6 V2", "OL M6 V3")
  ) %>% 
  arrange(correlacion, n, Tipo_Sim)

5.4 Data format for evaluation

df_work_tidy_A <- df_work_tidy_evaluate %>% 
  select(correlacion:Tipo_Sim, Normal_multi_r:norm_uni) %>%
  pivot_longer(
    cols = Normal_multi_r:norm_uni,
    names_to = "Evaluación Normalidad",
    values_to = "Dx"
  ) %>%
  mutate(
    `Evaluación Normalidad` = ifelse(`Evaluación Normalidad` == "Normal_multi_r",
                                     "Normalidad mardia", "Normalidad As y Ks")
  )

5.5 Plots

5.5.1 Plot Mardia

Calculate the percentage of dataframes identified as multivariate normal in each condition.

df_work_tidy_A_mardia <- df_work_tidy_A %>% 
  filter(`Evaluación Normalidad` == "Normalidad mardia") %>% 
  count(correlacion, n, Tipo_Sim,
        Dx, name = "Cantidad") %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  mutate(Porcentaje = Cantidad/sum(Cantidad)) %>% 
  select(-Cantidad) %>% 
  pivot_wider(
    names_from = Dx,
    values_from = Porcentaje,
    values_fill = 0
  ) %>% 
  ungroup()

df_work_tidy_A_mardia

Plot generation:

plot_A_mardia <- df_work_tidy_A_mardia %>% 
  mutate(correlacion = factor(correlacion,
                              labels = c("0.12", "0.20",
                                         "0.31", "0.50")),
         correlacion = fct_rev(correlacion)) %>% 
  ggplot(aes(x = Si, y = correlacion,
             alpha = correlacion, label = scales::percent(Si, 
                                                          accuracy = 1))) +
  geom_col() +
  facet_grid(n ~ Tipo_Sim)  +
  scale_alpha_discrete(
    name = "Correlación",
    guide = guide_legend(reverse = TRUE)
  ) + 
  scale_x_continuous(
    limits = c(0, 1),
    breaks = c(0, 0.25, 0.50, 0.75, 1),
    labels = scales::percent_format(),
    expand = c(0, 0.1),
    guide = guide_axis(n.dodge = 2)
  ) +
  geom_label(
    size = 3.5,
    label.size = 0.25, 
    label.r = unit(0.15, "lines"),
    label.padding = unit(0.15, "lines"),
    position = position_stack(vjust = 0.5),
    show.legend = FALSE
  ) +
  labs(
    y = "",
    x = ""
  ) + 
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 11,
      face="plain",
      colour="black"),
    legend.title = element_text(
      size = 11,
      face = "bold"
    ),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=11),
    strip.text = element_text(
      face="plain",
      colour="black",
      size=11),
    panel.spacing = unit(0.6, "lines")
  ) 

5.5.2 Plot Skewness and Kurtosis

Calculate the percentage of dataframes identified as univariate normality in each condition.

df_work_tidy_A_as_ks <- df_work_tidy_A %>% 
  filter(`Evaluación Normalidad` == "Normalidad As y Ks") %>% 
  count(correlacion, n, Tipo_Sim,
        Dx, name = "Cantidad") %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  mutate(Porcentaje = Cantidad/sum(Cantidad)) %>% 
  select(-Cantidad) %>% 
  pivot_wider(
    names_from = Dx,
    values_from = Porcentaje,
    values_fill = 0
  ) %>% 
  ungroup()

Plot generation:

plot_A_as_ks <- df_work_tidy_A_as_ks %>% 
  mutate(correlacion = factor(correlacion,
                              labels = c("0.12", "0.20",
                                         "0.31", "0.50")),
         correlacion = fct_rev(correlacion)) %>% 
  ggplot(aes(x = Si, y = correlacion,
             alpha = correlacion, label = scales::percent(Si, 
                                                          accuracy = 1))) +
  geom_col() +
  facet_grid(n ~ Tipo_Sim)  +
  scale_alpha_discrete(
    name = "Correlación",
    guide = guide_legend(reverse = TRUE)
  ) + 
  scale_x_continuous(
    limits = c(0, 1),
    breaks = c(0, 0.25, 0.50, 0.75, 1),
    labels = scales::percent_format(),
    expand = c(0, 0.1),
    guide = guide_axis(n.dodge = 2)
  ) +
  geom_label(
    size = 3.5,
    label.size = 0.25, 
    label.r = unit(0.15, "lines"),
    label.padding = unit(0.15, "lines"),
    position = position_stack(vjust = 0.5),
    show.legend = FALSE
  ) +
  labs(
    y = "",
    x = ""
  ) + 
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 11,
      face="plain",
      colour="black"),
    legend.title = element_text(
      size = 11,
      face = "bold"
    ),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=11),
    strip.text = element_text(
      face="plain",
      colour="black",
      size=11),
    panel.spacing = unit(0.6, "lines")
  ) 

LS0tCnRpdGxlOiAiU2ltdWxhdGlvbiBvZiBjb3JyZWxhdGlvbiBlc3RpbWF0b3JzIGZvciBub3JtYWwgYW5kIG5vbi1ub3JtYWwgY29ycmVsYXRpb25zIgpkYXRlOiAiMDMvMDQvMjAyMSIKYXV0aG9yOgogIC0gbmFtZTogSm9zw6kgVmVudHVyYS1MZcOzbgogICAgZW1haWw6IGpvc2UudmVudHVyYUB1cG4ucGUKICAgIGFmZmlsaWF0aW9uOiBVbml2ZXJzaWRhZCBQcml2YWRhIGRlbCBOb3J0ZQogIC0gbmFtZTogQnJpYW4gTi4gUGXDsWEtQ2FsZXJvCiAgICBlbWFpbDogYnJpYW5tc21AZ21haWwuY29tCiAgICBhZmZpbGlhdGlvbjogR3J1cG8gZGUgRXN0dWRpb3MgQXZhbmNlcyBlbiBNZWRpY2nDs24gUHNpY29sw7NnaWNhLCBVbml2ZXJzaWRhZCBOYWNpb25hbCBNYXlvciBkZSBTYW4gTWFyY29zLCBMaW1hLCBQZXLDugpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgaGlnaGxpZ2h0OiBrYXRlCiAgICB0aGVtZTogZmxhdGx5Ci0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgojIFByZXBhcmF0aW9ucyBmb3IgYW5hbHlzaXMKCkxvYWRpbmcgcGFja2FnZXMgdG8gc2ltdWxhdGUgYW5kIG1hbmlwdWxhdGUgZGF0YS4gCgpgYGB7cn0KbGlicmFyeShNQVNTKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgoKIyBTaW11bGF0ZSBkYXRhCgpEYXRhIGdlbmVyYXRpb24gd2FzIHBlcmZvcm1lZCBhY2NvcmRpbmcgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKLSBDb3JyZWxhdGlvbnM6IDAuMTIsIDAuMjAsIDAuMzEsIDAuNTAKLSBTYW1wbGUgc2l6ZXM6IDUwLCAxMDAsIDI1MCwgNTAwLCAxMDAwCi0gTnVtYmVyIG9mIHJlcGxpY2F0aW9uczogMTAwMAoKSW4gdGhpcyB3YXksIDIwICpkYXRhZnJhbWVzKiBhcmUgZ2VuZXJhdGVkIHdpdGggZGlmZmVyZW50IGFtb3VudHMgb2YgZGF0YSB3aXRoaW4gZWFjaCBvZiB0aGVtLCB3aGljaCB3aWxsIGhhdmUgMSwwMDAgKnJlcGxpY2F0aW9ucyouIEluIHRvdGFsLCAyMCwwMDAgKmRhdGFmcmFtZXMqIHdpdGggb2JzZXJ2YXRpb25zIGZvciBhbmFseXNpcy4KCgojIyBHZW5lcmF0ZSBtYXRyaWNlcyBhbmQgb2JzZXJ2YXRpb25zCgpDcmVhdGUgdGhlIHZhcmlhYmxlcyB0aGF0IGluZGljYXRlIHRoZSBjb25kaXRpb25zCgpgYGB7cn0Kc2V0LnNlZWQoMjAyMCkgCnIgPC0gYygwLjEyLCAwLjIwLCAwLjMxLCAwLjUwKSAjIyBDb3JyZWxhdGlvbnMgCm4gPC0gYyg1MCwgMTAwLCAyNTAsIDUwMCwgMTAwMCkgIyMgU2FtcGxlIHNpemVzCnJlcGxpYyA8LSAxMDAwCmBgYAoKCmBgYHtyfQpzaWdtYSA8LSBsaXN0KCkKZm9yIChpIGluIHNlcV9hbG9uZyhyKSkgeyAKICBzaWdtYVtbaV1dIDwtIG1hdHJpeChkYXRhID0gYygxLCByZXAocltpXSwgMiksIDEpLAogICAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSAyLAogICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAyKQp9CgoKIyBHZW5lcmFyIGxvcyBkYXRvcyBkZSBjb3JyZWxhY2nDs24KZGZfY29yIDwtIGxpc3QoKQpmb3IgKGkgaW4gc2VxX2Fsb25nKHNpZ21hKSkgewogIGRmX2NvcltbaV1dIDwtIGxpc3QoKQogIGZvciAoaiBpbiBzZXFfYWxvbmcobikpIHsKICAgIGRmX2NvcltbaV1dW1tqXV0gPC0gbGlzdCgpCiAgICBmb3IgKGsgaW4gMTpyZXBsaWMpIHsKICAgICAgZGZfY29yW1tpXV1bW2pdXVtba11dIDwtIG12cm5vcm0obiAgICAgPSBuW2pdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCgwLCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSBzaWdtYVtbaV1dKSAlPiUgCiAgICAgICAgYXNfdGliYmxlKCkKICAgIH0KICB9Cn0KYGBgCgojIyBGb3JtYXQgdGhlIGRhdGEgYXMgZGF0YWZyYW1lIC8gdGliYmxlcwoKV2Ugd2lsbCBhc3NlbWJsZSB0aGUgbGlzdCBvYmplY3QgaW4gc3VjaCBhIHdheSB0aGF0IHdlIGNhbiBpZGVudGlmeSBieSBjb2x1bW5zIHRoZSBjb3JyZWxhdGlvbiwgc2FtcGxlIHNpemUgYW5kIHJlcGxpY2F0ZSBudW1iZXIgb2YgZWFjaCBvYnNlcnZhdGlvbi4KCmBgYHtyfQojIFVuaXIgbG9zIGRhdG9zIHkgcGFzYXJsbyBhIGZvcm1hdG8gdGlkeQp0ZW1wIDwtIGRmX2NvcgpkZl9jb3IgPC0gbGlzdCgpCmZvciAoaSBpbiBzZXFfYWxvbmcoc2lnbWEpKSB7CiAgZGZfY29yW1tpXV0gPC0gbGlzdCgpCiAgZm9yIChqIGluIHNlcV9hbG9uZyhuKSkgewogICAgZGZfY29yW1tpXV1bW2pdXSA8LSB0ZW1wW1tpXV1bW2pdXSAlPiUgCiAgICAgIGJpbmRfcm93cyguaWQgPSAicmVwbGljIikgJT4lIAogICAgICBtdXRhdGUocmVwbGljID0gYXMubnVtZXJpYyhyZXBsaWMpKQogIH0KICBkZl9jb3JbW2ldXSA8LSBkZl9jb3JbW2ldXSAlPiUgCiAgICBiaW5kX3Jvd3MoLmlkID0gIm4iKSAlPiUgCiAgICBtdXRhdGUobiA9IHJlY29kZShuLCAiMSIgPSA1MCwgIjIiID0gMTAwLAogICAgICAgICAgICAgICAgICAgICAgIjMiID0gMjUwLCAiNCIgPSA1MDAsIAogICAgICAgICAgICAgICAgICAgICAgIjUiID0gMTAwMCkpCn0KCmRmX2NvciA8LSBkZl9jb3IgJT4lIAogIGJpbmRfcm93cyguaWQgPSAiY29ycmVsYWNpb24iKSAlPiUgCiAgbXV0YXRlKGNvcnJlbGFjaW9uID0gcmVjb2RlKGNvcnJlbGFjaW9uLCAiMSIgPSAwLjEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMiIgPSAwLjIwLCAiMyIgPSAwLjMxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNCIgPSAwLjUwKSkgJT4lIAogIGFycmFuZ2UoY29ycmVsYWNpb24sIG4sIHJlcGxpYykKCiMgQ3JlYXIgZGF0YSBuZXN0CmRmX25lc3QgPC0gZGZfY29yICU+JSAKICBuZXN0KGRhdGEgPSBjKFYxLCBWMikpCgpybSh0ZW1wLCBpLCBqLCBrKQpgYGAKCiMjIEFkZCBvdXRsaWVycyAKCkZpdmUgcGVyY2VudCBvZiB0aGUgZGF0YSBpbiBlYWNoIGRhdGEgZnJhbWUgd2lsbCBiZSByYW5kb21seSByZXBsYWNlZCBieSBvdXRsaWVyIGNvcnJlbGF0aW9ucyBkaWZmZXJlbnQgZnJvbSB0aGUgb25lIGdlbmVyYXRlZC4gRm9yIGV4YW1wbGUsIGluIHRoZSBjYXNlIG9mIGEgZGF0YWZyYW1lIHdpdGggYSBjb3JyZWxhdGlvbiBvZiAwLjEyIGFuZCBhIHNhbXBsZSBzaXplIG9mIDUwLCAzIHBhaXJzIG9mIGNvcnJlbGF0aW9ucyB3aWxsIGJlIHJhbmRvbWx5IHJlcGxhY2VkIHdpdGggMyBwYWlycyBvZiBjb3JyZWxhdGlvbnMgZ2VuZXJhdGVkIHdpdGggY29ycmVsYXRpb25zIG9mIDAuMjAsIDAuMzEgYW5kIDAuNTAuCgpgYGB7cn0KIyBBZGQgdGhlIG51bWJlciBvZiBvdXRsaWVycyB0byBiZSBhZGRlZCBhbmQgdGhlaXIgbG9jYXRpb25zIE91dGxpZXJzIGF0IDUlLgpkZl93b3JrIDwtIGRmX25lc3QgJT4lIAogIHJvd3dpc2UoKSAlPiUgCiAgbXV0YXRlKAogICAgcmF0aW9fb3V0bGllciA9IG1hcF9kYmwobiwKICAgICAgICAgICAgICAgICAgICAgICAgfiBjZWlsaW5nKDAuMDUqbikpLAogICAgcG9zaWNpX3JlcF9tMyA9IG1hcDIobiwgcmF0aW9fb3V0bGllciwKICAgICAgICAgICAgICAgICAgICAgICAgIH4gc2FtcGxlKDE6LngsIC55KSksCiAgICBwb3NpY2lfcmVwX202ID0gbWFwMihuLCByYXRpb19vdXRsaWVyLAogICAgICAgICAgICAgICAgICAgICAgICAgfiBzYW1wbGUoMToueCwgLnkpKSwKICAgIHBvc2ljaV9yZXBfbTN2MSA9IG1hcDIobiwgcmF0aW9fb3V0bGllciwKICAgICAgICAgICAgICAgICAgICAgICAgICB+IHNhbXBsZSgxOi54LCAueSkpLAogICAgcG9zaWNpX3JlcF9tM3YyID0gbWFwMihuLCByYXRpb19vdXRsaWVyLAogICAgICAgICAgICAgICAgICAgICAgICAgIH4gc2FtcGxlKDE6LngsIC55KSksCiAgICBwb3NpY2lfcmVwX20zdjMgPSBtYXAyKG4sIHJhdGlvX291dGxpZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgfiBzYW1wbGUoMToueCwgLnkpKSwKICAgIHBvc2ljaV9yZXBfbTZ2MSA9IG1hcDIobiwgcmF0aW9fb3V0bGllciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgfiBzYW1wbGUoMToueCwgLnkpKSwKICAgIHBvc2ljaV9yZXBfbTZ2MiA9IG1hcDIobiwgcmF0aW9fb3V0bGllciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgfiBzYW1wbGUoMToueCwgLnkpKSwKICAgIHBvc2ljaV9yZXBfbTZ2MyA9IG1hcDIobiwgcmF0aW9fb3V0bGllciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgfiBzYW1wbGUoMToueCwgLnkpKQogICkKCiMgQWRkIGNvcnJlbGF0aW9ucyB0aGF0IHdlcmUgbm90IGNvbnNpZGVyZWQKZGZfd29yayA8LSBkZl93b3JrICU+JSAKICBtdXRhdGUoCiAgICBjb3JyZWxhX2EgPSByW3doaWNoKGNvcnJlbGFjaW9uICE9IHIpWzFdXSwKICAgIGNvcnJlbGFfYiA9IHJbd2hpY2goY29ycmVsYWNpb24gIT0gcilbMl1dLAogICAgY29ycmVsYV9jID0gclt3aGljaChjb3JyZWxhY2lvbiAhPSByKVszXV0KICApCmBgYAoKT24gdGhlIGNvcnJlbGF0aW9ucyBpZGVudGlmaWVkIHRvIGJlIGdlbmVyYXRlZCwgdGhlIGRhdGEgbWF0cml4IG5lY2Vzc2FyeSBmb3IgdGhlIG11bHRpdmFyaWF0ZSBzaW11bGF0aW9uIGlzIGNyZWF0ZWQgYXMgYW4gb3V0bGllci4KCmBgYHtyfQpkZl93b3JrIDwtIGRmX3dvcmsgJT4lIAogIG11dGF0ZSgKICAgIG1hdHJpeCA9IG1hcChjb3JyZWxhY2lvbiwKICAgICAgICAgICAgICAgICB+IG1hdHJpeChkYXRhID0gcmVwKGMoMSwgcmVwKC54LCAyKSksIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBucm93ID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMikpLAogICAgbWF0cml4X2EgPSBtYXAoY29ycmVsYV9hLAogICAgICAgICAgICAgICAgICAgfiBtYXRyaXgoZGF0YSA9IHJlcChjKDEsIHJlcCgueCwgMikpLCAyKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBucm93ID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAyKSksCiAgICBtYXRyaXhfYiA9IG1hcChjb3JyZWxhX2IsCiAgICAgICAgICAgICAgICAgICB+IG1hdHJpeChkYXRhID0gcmVwKGMoMSwgcmVwKC54LCAyKSksIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDIpKSwKICAgIG1hdHJpeF9jID0gbWFwKGNvcnJlbGFfYywKICAgICAgICAgICAgICAgICAgIH4gbWF0cml4KGRhdGEgPSByZXAoYygxLCByZXAoLngsIDIpKSwgMiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbnJvdyA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMikpCiAgKSAlPiUgCiAgdW5ncm91cCgpCmBgYAoKQWdncmVnYXRlIG91dGxpZXJzIGFyZSBvZiAyIHR5cGVzOiB0aGV5IHZhcnkgb25seSBieSB0aGUgbWVhbiBhbmQgdGhleSB2YXJ5IGJ5IHRoZSBtZWFuIGFuZCBpdHMgbWF0cml4OgoKLSBvdXRsaWVyX20zOiBWYXJpZXMgYnkgYW4gbWVhbiBvZiAzIAotIG91dGxpZXJfbTY6IFZhcmllcyBieSBhbiBtZWFuIG9mIDYKLSBvdXRsaWVyX20zdjE6IFZhcmllcyBieSBhbiBtZWFuIG9mIDMgYW5kIG1hdHJpeCBhCi0gb3V0bGllcl9tM3YyOiBWYXJpZXMgYnkgYW4gbWVhbiBvZiAzIGFuZCBtYXRyaXggYgotIG91dGxpZXJfbTN2MzogVmFyaWVzIGJ5IGFuIG1lYW4gb2YgMyBhbmQgbWF0cml4IGMKLSBvdXRsaWVyX202djE6IFZhcmllcyBieSBhbiBtZWFuIG9mIDYgYW5kIG1hdHJpeCBhCi0gb3V0bGllcl9tNnYyOiBWYXJpZXMgYnkgYW4gbWVhbiBvZiA2IGFuZCBtYXRyaXggYgotIG91dGxpZXJfbTZ2MzogVmFyaWVzIGJ5IGFuIG1lYW4gb2YgNiBhbmQgbWF0cml4IGMKCmBgYHtyfQpzZXQuc2VlZCgyMDE5KSAKCmRmX3dvcmsgPC0gZGZfd29yayAlPiUgCiAgbXV0YXRlKAogICAgb3V0bGllcl9tMyA9IG1hcDIocmF0aW9fb3V0bGllciwgbWF0cml4LCAKICAgICAgICAgICAgICAgICAgICAgIH4gbXZybm9ybShuICAgICA9IC54LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11ICAgID0gcmVwKDMsIDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgYXNfdGliYmxlKCkpLAogICAgb3V0bGllcl9tNiA9IG1hcDIocmF0aW9fb3V0bGllciwgbWF0cml4LAogICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXUgICAgPSByZXAoNiwgMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSAueSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBvdXRsaWVyX20zdjEgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeF9hLCAKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCgzLCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBvdXRsaWVyX20zdjIgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeF9iLCAKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCgzLCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBvdXRsaWVyX20zdjMgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeF9jLCAKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCgzLCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBvdXRsaWVyX202djEgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeF9hLCAKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCg2LCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBvdXRsaWVyX202djIgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeF9iLCAKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCg2LCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBvdXRsaWVyX202djMgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeF9jLCAKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCg2LCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSkKICApCmBgYAoKVGhlc2UgbmV3IHNpbXVsYXRlZCBvdXRsaWVyIGNvcnJlbGF0aW9ucyB3aWxsIGJlIGluc2VydGVkIGludG8gdGhlIGluaXRpYWxseSBjYWxjdWxhdGVkIHJhbmRvbSBwb3NpdGlvbnMgaW4gZWFjaCBkYXRhZnJhbWUuCgpgYGB7cn0KZGZfd29yayA8LSBkZl93b3JrICU+JSAKICBtdXRhdGUoCiAgICBkYXRhX291dF9tMyA9IHBtYXAobGlzdChkYXRhLCBwb3NpY2lfcmVwX20zLCBvdXRsaWVyX20zKSwKICAgICAgICAgICAgICAgICAgICAgICB+IC4uMSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICBzbGljZSgtIC4uMikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgYmluZF9yb3dzKC4uMykpLAogICAgZGF0YV9vdXRfbTYgPSBwbWFwKGxpc3QoZGF0YSwgcG9zaWNpX3JlcF9tNiwgb3V0bGllcl9tNiksCiAgICAgICAgICAgICAgICAgICAgICAgfiAuLjEgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgc2xpY2UoLSAuLjIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgIGJpbmRfcm93cyguLjMpKSwKICAgIGRhdGFfb3V0X20zdjEgPSBwbWFwKGxpc3QoZGF0YSwgcG9zaWNpX3JlcF9tM3YxLCBvdXRsaWVyX20zdjEpLAogICAgICAgICAgICAgICAgICAgICAgICAgfiAuLjEgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzbGljZSgtIC4uMikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5kX3Jvd3MoLi4zKSksCiAgICBkYXRhX291dF9tM3YyID0gcG1hcChsaXN0KGRhdGEsIHBvc2ljaV9yZXBfbTN2Miwgb3V0bGllcl9tM3YyKSwKICAgICAgICAgICAgICAgICAgICAgICAgIH4gLi4xICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xpY2UoLSAuLjIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgYmluZF9yb3dzKC4uMykpLAogICAgZGF0YV9vdXRfbTN2MyA9IHBtYXAobGlzdChkYXRhLCBwb3NpY2lfcmVwX20zdjMsIG91dGxpZXJfbTN2MyksCiAgICAgICAgICAgICAgICAgICAgICAgICB+IC4uMSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsaWNlKC0gLi4yKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpbmRfcm93cyguLjMpKSwKICAgIGRhdGFfb3V0X202djEgPSBwbWFwKGxpc3QoZGF0YSwgcG9zaWNpX3JlcF9tNnYxLCBvdXRsaWVyX202djEpLAogICAgICAgICAgICAgICAgICAgICAgICAgfiAuLjEgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzbGljZSgtIC4uMikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5kX3Jvd3MoLi4zKSksCiAgICBkYXRhX291dF9tNnYyID0gcG1hcChsaXN0KGRhdGEsIHBvc2ljaV9yZXBfbTZ2Miwgb3V0bGllcl9tNnYyKSwKICAgICAgICAgICAgICAgICAgICAgICAgIH4gLi4xICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xpY2UoLSAuLjIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgYmluZF9yb3dzKC4uMykpLAogICAgZGF0YV9vdXRfbTZ2MyA9IHBtYXAobGlzdChkYXRhLCBwb3NpY2lfcmVwX202djMsIG91dGxpZXJfbTZ2MyksCiAgICAgICAgICAgICAgICAgICAgICAgICB+IC4uMSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsaWNlKC0gLi4yKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpbmRfcm93cyguLjMpKQogICkKYGBgCgpBZGRpdGlvbmFsbHksIG5ldyBkYXRhZnJhbWVzIHdpdGggdGhlIHNhbWUgY29ycmVsYXRpb24gY29uZGl0aW9ucywgc2FtcGxlIHNpemUgYW5kIG51bWJlciBvZiByZXBsaWNhdGlvbnMgd2l0aCBub24tbm9ybWFsIGRhdGEgZGlzdHJpYnV0aW9ucyBhcmUgZ2VuZXJhdGVkIHVzaW5nIHRoZSBhbGdvcml0aG0gb2YgVmFsZSBhbmQgTWF1cmVsbGkgKDE5ODMpLiAKCk5vbi1ub3JtYWxpdHkgY29uZGl0aW9ucyB3ZXJlIGdlbmVyYXRlZCBvbiB0aGUgYmFzaXMgb2YgdGhlIHdvcmsgb2YgW1NoZW5nICYgU2hlbmcgKDIwMTIpXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUMzMjc5NzI0Lyk6CgotIHNrZXduZXNzID0gMC4wMCwga3VydG9zaXMgPSDiiJIgMS4zODUgKHN5bW1ldHJpYyBwbGF0eWt1cnRpYyBkaXN0cmlidXRpb24pOwotIHNrZXduZXNzID0gMC4wMCwga3VydG9zaXMgPSAyNSAoc3ltbWV0cmljIGxlcHRva3VydGljIGRpc3RyaWJ1dGlvbik7Ci0gc2tld25lc3MgPSAwLjk2LCBrdXJ0b3NpcyA9IDAuMTMgKG5vbi1zeW1tZXRyaWMgZGlzdHJpYnV0aW9uKTsKLSBza2V3bmVzcyA9IDAuNDgsIGt1cnRvc2lzID0g4oiSIDAuOTIgKG5vbi1zeW1tZXRyaWMgcGxhdHlrdXJ0aWMgZGlzdHJpYnV0aW9uKTsKLSBza2V3bmVzcyA9IDIuNTAsIGt1cnRvc2lzID0gMjUgKG5vbi1zeW1tZXRyaWMgbGVwdG9rdXJ0aWMgZGlzdHJpYnV0aW9uKS4KCmBgYHtyfQpzZXQuc2VlZCgyMDIxKSAKbGlicmFyeShzZW1Ub29scykKCmRmX3dvcmsgPC0gZGZfd29yayAlPiUgCiAgbXV0YXRlKAogICAgZGF0YV9ub25vcm0xID0gbWFwMihuLCBtYXRyaXgsCiAgICAgICAgICAgICAgICAgICAgICAgIH4gbXZybm9ubm9ybShuID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSA9IHJlcCgwLCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBza2V3bmVzcyA9IGMoMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrdXJ0b3NpcyA9IGMoLTEuMzg1KSkgJT4lICMgc3ltbWV0cmljIHBsYXR5a3VydGljIGRpc3RyaWJ1dGlvbgogICAgICAgICAgICAgICAgICAgICAgICAgIGFzX3RpYmJsZSgpKSwKICAgIGRhdGFfbm9ub3JtMiA9IG1hcDIobiwgbWF0cml4LAogICAgICAgICAgICAgICAgICAgICAgICB+IG12cm5vbm5vcm0obiA9IC54LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXUgPSByZXAoMCwgMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTaWdtYSA9IC55LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2tld25lc3MgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga3VydG9zaXMgPSAyNSkgJT4lICMgc3ltbWV0cmljIGxlcHRva3VydGljIGRpc3RyaWJ1dGlvbiAKICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBkYXRhX25vbm9ybTMgPSBtYXAyKG4sIG1hdHJpeCwKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub25ub3JtKG4gPSAueCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11ID0gcmVwKDAsIDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSAueSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNrZXduZXNzID0gMC45NiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGt1cnRvc2lzID0gMC4xMykgJT4lICMgbm9uLXN5bW1ldHJpYyBkaXN0cmlidXRpb24KICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksCiAgICBkYXRhX25vbm9ybTQgPSBtYXAyKG4sIG1hdHJpeCwKICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub25ub3JtKG4gPSAueCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11ID0gcmVwKDAsIDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSAueSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNrZXduZXNzID0gMC40OCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGt1cnRvc2lzID0gLTAuOTIpICU+JSAjIG5vbi1zeW1tZXRyaWMgcGxhdHlrdXJ0aWMgZGlzdHJpYnV0aW9uCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXNfdGliYmxlKCkpLAogICAgZGF0YV9ub25vcm01ID0gbWFwMihuLCBtYXRyaXgsCiAgICAgICAgICAgICAgICAgICAgICAgIH4gbXZybm9ubm9ybShuID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSA9IHJlcCgwLCAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBza2V3bmVzcyA9IDIuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGt1cnRvc2lzID0gMjUpICU+JSAjIG5vbi1zeW1tZXRyaWMgbGVwdG9rdXJ0aWMgZGlzdHJpYnV0aW9uCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXNfdGliYmxlKCkpCiAgKQpgYGAKCkZpbmFsbHksIHRoZSB2YXJpYWJsZXMgdGhhdCB3aWxsIG5vIGxvbmdlciBiZSB1c2VkIGFyZSBlbGltaW5hdGVkLgoKYGBge3J9CmRmX3dvcmsgPC0gZGZfd29yayAlPiUgCiAgc2VsZWN0KC1jKHJhdGlvX291dGxpZXI6b3V0bGllcl9tNnYzKSkKYGBgCgoKIyBDYWxjdWxhdGlvbiBvZiBjb3JyZWxhdGlvbnMKCiMjIEZvcm1hdCB0aWR5IGRhdGEKYGBge3J9CmRmX3dvcmtfdGlkeSA8LSBkZl93b3JrICU+JSAKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gZGF0YTpkYXRhX25vbm9ybTUsCiAgICBuYW1lc190byA9ICJUaXBvX1NpbSIsCiAgICB2YWx1ZXNfdG8gPSAiRGF0YSIKICApCmBgYAoKIyMgQ29ycmVsYXRpb25zCgpgYGB7cn0KbGlicmFyeShXUlMyKQpkZl93b3JrX3RpZHkgPC0gZGZfd29ya190aWR5ICU+JSAKICBtdXRhdGUoCiAgICBjb3J0X3BlYXJzID0gbWFwKERhdGEsCiAgICAgICAgICAgICAgICAgICAgIH4gY29yLnRlc3QoLngkVjEsIC54JFYyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJwZWFyc29uIikpLAogICAgY29ydF9zcGVhciA9IG1hcChEYXRhLAogICAgICAgICAgICAgICAgICAgICB+IGNvci50ZXN0KC54JFYxLCAueCRWMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAic3BlYXJtYW4iKSksCiAgICBjb3J0X3dpbnNvID0gbWFwKERhdGEsCiAgICAgICAgICAgICAgICAgICAgIH4gd2luY29yKC54JFYxLCAueCRWMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHIgPSAwLjIpKQogICkKYGBgCgojIyBPYnRhaW4gdGhlIGNvZWZmaWNpZW50cwoKYGBge3J9CmRmX3dvcmtfdGlkeSA8LSBkZl93b3JrX3RpZHkgJT4lIAogIG11dGF0ZSgKICAgIGNvZWZfcGVhcnMgPSBtYXBfZGJsKGNvcnRfcGVhcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICB+IC54JGVzdGltYXRlWzFdKSwKICAgIGNvZWZfc3BlYXIgPSBtYXBfZGJsKGNvcnRfc3BlYXIsCiAgICAgICAgICAgICAgICAgICAgICAgICB+IC54JGVzdGltYXRlWzFdKSwKICAgIGNvZWZfd2luc28gPSBtYXBfZGJsKGNvcnRfd2luc28sCiAgICAgICAgICAgICAgICAgICAgICAgICB+IC54JGNvclsxXSkKICApCgpkZl93b3JrX3RpZHlfc2ltcCA8LSBkZl93b3JrX3RpZHkgJT4lIAogIHNlbGVjdCgtYyhEYXRhOmNvcnRfd2luc28pKQpgYGAKCiMgRXZhbHVhdGUgc2ltdWxhdGlvbgoKIyMgQ2FsY3VsYXRlIFJNU0VBIGFuZCBCaWFzCgpgYGB7cn0KZGZfd29ya190aWR5X3NpbXAgPC0gZGZfd29ya190aWR5X3NpbXAgJT4lIAogIHJvd3dpc2UoKSAlPiUgCiAgbXV0YXRlKAogICAgZGlmX3BlYXJzID0gKGNvZWZfcGVhcnMgLSBjb3JyZWxhY2lvbikvY29ycmVsYWNpb24sCiAgICBkaWZfc3BlYXIgPSAoY29lZl9zcGVhciAtIGNvcnJlbGFjaW9uKS9jb3JyZWxhY2lvbiwKICAgIGRpZl93aW5zbyA9IChjb2VmX3dpbnNvIC0gY29ycmVsYWNpb24pL2NvcnJlbGFjaW9uCiAgKSAlPiUgCiAgdW5ncm91cCgpCgpkZl93b3JrX3RpZHlfc2ltcCA8LSBkZl93b3JrX3RpZHlfc2ltcCAlPiUgCiAgZ3JvdXBfYnkoY29ycmVsYWNpb24sIG4sIFRpcG9fU2ltKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgcm1zZWFfcGVhcnMgPSBzcXJ0KHN1bShkaWZfcGVhcnNeMikvMTAwMCksCiAgICBzZXNnb19wZWFycyA9IChzdW0oZGlmX3BlYXJzKS8xMDAwKSwKICAgIHJtc2VhX3NwZWFyID0gc3FydChzdW0oZGlmX3NwZWFyXjIpLzEwMDApLAogICAgc2VzZ29fc3BlYXIgPSAoc3VtKGRpZl9zcGVhcikvMTAwMCksCiAgICBybXNlYV93aW5zbyA9IHNxcnQoc3VtKGRpZl93aW5zb14yKS8xMDAwKSwKICAgIHNlc2dvX3dpbnNvID0gKHN1bShkaWZfd2luc28pLzEwMDApCiAgKSAlPiUgCiAgdW5ncm91cCgpCgpkZl93b3JrX3RpZHlfc2ltcApgYGAKCiMjIFJlY29kZSBzaW11bGF0aW9uIHR5cGVzCgpgYGB7cn0KZGZfd29ya190aWR5X3NpbXAgPC0gZGZfd29ya190aWR5X3NpbXAgJT4lIAogIG11dGF0ZSgKICAgIFRpcG9fU2ltID0gZmN0X3JlY29kZShUaXBvX1NpbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIiA9ICJkYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTMiID0gImRhdGFfb3V0X20zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTYiID0gImRhdGFfb3V0X202IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTMgVjEiID0gImRhdGFfb3V0X20zdjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNMyBWMiIgPSAiZGF0YV9vdXRfbTN2MiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE0zIFYzIiA9ICJkYXRhX291dF9tM3YzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTYgVjEiID0gImRhdGFfb3V0X202djEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNNiBWMiIgPSAiZGF0YV9vdXRfbTZ2MiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IFYzIiA9ICJkYXRhX291dF9tNnYzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIEEiID0gImRhdGFfbm9ub3JtMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBCIiA9ICJkYXRhX25vbm9ybTIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJOby1NVk4gQyIgPSAiZGF0YV9ub25vcm0zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIEQiID0gImRhdGFfbm9ub3JtNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBFIiA9ICJkYXRhX25vbm9ybTUiKSwKICAgIFRpcG9fU2ltID0gZmN0X3JlbGV2ZWwoVGlwb19TaW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJNVk4iLCAiT0wgTTMiLCAiT0wgTTYiLCAiT0wgTTMgVjEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE0zIFYyIiwgIk9MIE0zIFYzIiwgIk9MIE02IFYxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IFYyIiwgIk9MIE02IFYzIikKICApICU+JSAKICBhcnJhbmdlKGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSkKYGBgCgojIyBDb21wbGV0ZSB0YWJsZSBhYm91dCBSTVNFQSBhbmQgQmlhcwoKYGBge3J9CmRmX3dvcmtfdGlkeV9zaW1wX0EgPC0gZGZfd29ya190aWR5X3NpbXAgJT4lIAogIHJlbG9jYXRlKGNvbnRhaW5zKCJzZXNnbyIpLCAuYWZ0ZXIgPSAicm1zZWFfd2luc28iKQoKZGZfd29ya190aWR5X3NpbXBfQQpgYGAKCiMjIFJlY2FsY3VsYXRpb24gb2YgUk1TRUEgYW5kIEJpYXMgZ3JvdXBpbmcgY29uZGl0aW9ucwoKYGBge3J9CmRmX3dvcmtfdGlkeV9zaW1wX0IgPC0gZGZfd29ya190aWR5X3NpbXAgJT4lCiAgbXV0YXRlKAogICAgVGlwb19TaW0gPSBmY3RfY29sbGFwc2UoVGlwb19TaW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIiA9ICJNVk4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiBPTCBNMyIgPSAiT0wgTTMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiBPTCBNNiIgPSAiT0wgTTYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiBPTCBNM1YiID0gYygiT0wgTTMgVjEiLCAiT0wgTTMgVjIiLCAiT0wgTTMgVjMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNVk4gT0wgTTZWIiA9IGMoIk9MIE02IFYxIiwgIk9MIE02IFYyIiwgIk9MIE02IFYzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIiA9IGMoIk5vLU1WTiBBIiwgIk5vLU1WTiBDIiwgIk5vLU1WTiBEIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIGtzKyIgPSBjKCJOby1NVk4gQiIsICJOby1NVk4gRSIpCiAgICApCiAgKSAlPiUgCiAgcmVsb2NhdGUoY29udGFpbnMoInNlc2dvIiksIC5hZnRlciA9ICJybXNlYV93aW5zbyIpCgpkZl93b3JrX3RpZHlfc2ltcF9CIDwtIGRmX3dvcmtfdGlkeV9zaW1wX0IgJT4lIAogIGdyb3VwX2J5KGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSkgJT4lIAogIHN1bW1hcmlzZSgKICAgIGFjcm9zcyhldmVyeXRoaW5nKCksIG1lYW4pCiAgKSAlPiUgCiAgdW5ncm91cCgpCgpkZl93b3JrX3RpZHlfc2ltcF9CCmBgYAoKIyMgRm9ybWF0IHRpZHkgZGF0YQoKYGBge3J9CmRmX3dvcmtfdGlkeV9zaW1wIDwtIGRmX3dvcmtfdGlkeV9zaW1wICU+JSAKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gcm1zZWFfcGVhcnM6c2VzZ29fd2luc28sCiAgICBuYW1lc190byA9ICJBanVzdGUiLAogICAgdmFsdWVzX3RvID0gIlZhbG9yIgogICkgJT4lIAogIG11dGF0ZSgKICAgIEFqdXN0ZSA9IGZjdF9yZWNvZGUoQWp1c3RlLAogICAgICAgICAgICAgICAgICAgICAgICAiUk1TRSBQZWFyc29uIiA9ICJybXNlYV9wZWFycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICJSTVNFIFNwZWFybWFuIiA9ICJybXNlYV9zcGVhciIsCiAgICAgICAgICAgICAgICAgICAgICAgICJSTVNFIFdpbnNvcml6ZWQiID0gInJtc2VhX3dpbnNvIiwKICAgICAgICAgICAgICAgICAgICAgICAgIlNlc2dvIFBlYXJzb24iID0gInNlc2dvX3BlYXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgIlNlc2dvIFNwZWFybWFuIiA9ICJzZXNnb19zcGVhciIsCiAgICAgICAgICAgICAgICAgICAgICAgICJTZXNnbyBXaW5zb3JpemVkIiA9ICJzZXNnb193aW5zbyIpCiAgKQpgYGAKCiMjIFBsb3RzCgoKYGBge3J9CnBsb3RfYXNzZXNzX0EgPC0gZGZfd29ya190aWR5X3NpbXAgJT4lCiAgbXV0YXRlKAogICAgY29ycmVsYWNpb24gPSBmYWN0b3IoY29ycmVsYWNpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMC4xMiIsICIwLjIwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjAuMzEiLCAiMC41MCIpKQogICkgJT4lIAogIGZpbHRlcihjb3JyZWxhY2lvbiAhPSAiMC41MCIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBUaXBvX1NpbSwgeSA9IFZhbG9yLAogICAgICAgICAgICAgIyBjb2xvdXIgPSBBanVzdGUsCiAgICAgICAgICAgICBzaGFwZSA9IEFqdXN0ZSwKICAgICAgICAgICAgIGxpbmV0eXBlID0gQWp1c3RlLAogICAgICAgICAgICAgZ3JvdXAgPSBBanVzdGUpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjM2EzYTNhIiwgc2l6ZSA9IDIpICsKICBnZW9tX3BhdGgoY29sb3IgPSAiIzNhM2EzYSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMC41LCA1LjUpLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoLTAuNSwgNS41LCAxKSkgKwogIGxhYnModGl0bGUgPSAiIiwKICAgICAgIHggPSAiQ29uZGljaW9uZXMgZGUgU2ltdWxhY2nDs24iLAogICAgICAgeSA9ICIiKSArCiAgIyBzY2FsZV94X2Rpc2NyZXRlKGd1aWRlID0gZ3VpZGVfYXhpcyhuLmRvZGdlID0gMikpICsKICBmYWNldF9ncmlkKGNvcnJlbGFjaW9uIH4gbikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiKSwKICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IDExLAogICAgICBmYWNlPSJib2xkIiksIAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gOSwKICAgICAgZmFjZT0icGxhaW4iLAogICAgICBjb2xvdXI9ImJsYWNrIiksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IDExLAogICAgICBtYXJnaW4gPSBtYXJnaW4odCA9IDcsIHIgPSAwLCBiID0gMCwgbCA9IDApCiAgICApLAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IDExCiAgICApLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIGZhY2U9InBsYWluIiwKICAgICAgY29sb3VyPSJibGFjayIsCiAgICAgIHNpemU9MTApLAogICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC44LCAibGluZXMiKQogICkgCmBgYAoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPScxMDAlJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImltZy9FdmFsdWF0ZV9jb3JyZWxhdGlvbl9STVNFQV9CaWFzX0EucG5nIikKYGBgCgpgYGB7cn0KcGxvdF9hc3Nlc3NfQiA8LSBkZl93b3JrX3RpZHlfc2ltcCAlPiUKICBtdXRhdGUoCiAgICBjb3JyZWxhY2lvbiA9IGZhY3Rvcihjb3JyZWxhY2lvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwLjEyIiwgIjAuMjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMC4zMSIsICIwLjUwIikpCiAgKSAlPiUgCiAgZmlsdGVyKGNvcnJlbGFjaW9uICE9ICIwLjUwIikgJT4lIAogIGdncGxvdChhZXMoeCA9IFRpcG9fU2ltLCB5ID0gVmFsb3IsCiAgICAgICAgICAgICAjIGNvbG91ciA9IEFqdXN0ZSwKICAgICAgICAgICAgIHNoYXBlID0gQWp1c3RlLAogICAgICAgICAgICAgbGluZXR5cGUgPSBBanVzdGUsCiAgICAgICAgICAgICBncm91cCA9IEFqdXN0ZSkpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMzYTNhM2EiLCBzaXplID0gMikgKwogIGdlb21fcGF0aChjb2xvciA9ICIjM2EzYTNhIikgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0wLjUsIDUuNSksCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgtMC41LCA1LjUsIDEpKSArCiAgbGFicyh0aXRsZSA9ICIiLAogICAgICAgeCA9ICJDb25kaWNpb25lcyBkZSBTaW11bGFjacOzbiIsCiAgICAgICB5ID0gIiIpICsKICAjIHNjYWxlX3hfZGlzY3JldGUoZ3VpZGUgPSBndWlkZV9heGlzKG4uZG9kZ2UgPSAyKSkgKwogIGZhY2V0X2dyaWQobiB+IGNvcnJlbGFjaW9uKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2UgPSAiYm9sZCIpLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEsCiAgICAgIGZhY2U9ImJvbGQiKSwgCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSA5LAogICAgICBmYWNlPSJwbGFpbiIsCiAgICAgIGNvbG91cj0iYmxhY2siKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEsCiAgICAgIG1hcmdpbiA9IG1hcmdpbih0ID0gNywgciA9IDAsIGIgPSAwLCBsID0gMCkKICAgICksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEKICAgICksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgZmFjZT0icGxhaW4iLAogICAgICBjb2xvdXI9ImJsYWNrIiwKICAgICAgc2l6ZT0xMCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjgsICJsaW5lcyIpCiAgKSAKYGBgCgpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGg9JzEwMCUnfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1nL0V2YWx1YXRlX2NvcnJlbGF0aW9uX1JNU0VBX0JpYXNfQi5wbmciKQpgYGAKCiMgRXZhbHVhdGUgbm9ybWFsaXR5CgojIyBDYWxjdWxhdGlvbiBvZiBrdXJ0b3NpcyBhbmQgc2tld25lc3MgZm9yIGVhY2ggdmFyaWFibGUKCmBgYHtyfQpsaWJyYXJ5KGUxMDcxKQoKZGZfd29ya190aWR5X2V2YWx1YXRlIDwtIGRmX3dvcmtfdGlkeSAlPiUgCiAgbXV0YXRlKAogICAga3VydG9zaXNfdjEgPSBtYXBfZGJsKERhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgfiBrdXJ0b3NpcygueCRWMSwgdHlwZSA9IDIpKSwKICAgIGt1cnRvc2lzX3YyID0gbWFwX2RibChEYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgIH4ga3VydG9zaXMoLngkVjIsIHR5cGUgPSAyKSksCiAgICBza2V3bmVzc192MSA9IG1hcF9kYmwoRGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICB+IHNrZXduZXNzKC54JFYxLCB0eXBlID0gMikpLAogICAgc2tld25lc3NfdjIgPSBtYXBfZGJsKERhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgfiBza2V3bmVzcygueCRWMiwgdHlwZSA9IDIpKQogICkgJT4lIAogIHNlbGVjdCgtYyhjb3J0X3BlYXJzOmNvZWZfd2luc28pKQoKZGZfd29ya190aWR5X2V2YWx1YXRlCmBgYAoKIyMgQ2FsY3VsYXRpb24gZXZhbHVhdGluZyBtdWx0aXZhcmlhdGUgbm9ybWFsaXR5CgojIyMgU2V0dGluZ3MgbXVsdGljb3JlCmBgYHtyfQpsaWJyYXJ5KG11bHRpZHBseXIpCgppZiAoU3lzLmdldGVudigiUlNUVURJTyIpID09ICIxIiAmJiAhbnpjaGFyKFN5cy5nZXRlbnYoIlJTVFVESU9fVEVSTSIpKSAmJiAKICAgIChTeXMuaW5mbygpWyJzeXNuYW1lIl0gPT0gIkRhcndpbiIgfHwgU3lzLmluZm8oKVsic3lzbmFtZSJdID09ICJMaW51eCIpICYmIAogICAgZ2V0UnZlcnNpb24oKSA+PSAiNC4wLjAiKSB7CiAgcGFyYWxsZWw6OjpzZXREZWZhdWx0Q2x1c3Rlck9wdGlvbnMoc2V0dXBfc3RyYXRlZ3kgPSAic2VxdWVudGlhbCIpCn0KCmNsdXN0ZXIgPC0gbmV3X2NsdXN0ZXIocGFyYWxsZWw6OmRldGVjdENvcmVzKCkpCmBgYAoKIyMjIEV2YWx1YXRpb24KCmBgYHtyfQpkZl93b3JrX3RpZHlfZXZhbHVhdGUgPC0gZGZfd29ya190aWR5X2V2YWx1YXRlICU+JSAKICBwYXJ0aXRpb24oY2x1c3RlcikgJT4lIAogIG11dGF0ZSgKICAgIE5vcm1hbF9tdWx0aV9yID0gcHVycnI6Om1hcF9jaHIoRGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IE1WTjo6bXZuKC54KSRtdWx0aXZhcmlhdGVOb3JtYWxpdHkkUmVzdWx0WzNdKSwKICAgIE5vcm1hbF9tdWx0aV9yID0gaWZlbHNlKE5vcm1hbF9tdWx0aV9yID09ICJZRVMiLCAiU2kiLCAiTm8iKQogICkgJT4lIAogIGNvbGxlY3QoKQpgYGAKCiMjIyBDYXRlZ29yaXplIGJ5IGt1cnRvc2lzIGFuZCBza2V3bmVzcwoKYGBge3J9CmRmX3dvcmtfdGlkeV9ldmFsdWF0ZSA8LSBkZl93b3JrX3RpZHlfZXZhbHVhdGUgJT4lIAogIG11dGF0ZSgKICAgIG5vcm1fdW5pID0gaWZlbHNlKGt1cnRvc2lzX3YxID49IC0gMS41ICYga3VydG9zaXNfdjEgPD0gMS41ICYKICAgICAgICAgICAgICAgICAgICAgICAgc2tld25lc3NfdjEgPj0gLSAxLjUgJiBza2V3bmVzc192MSA8PSAxLjUgJgogICAgICAgICAgICAgICAgICAgICAgICBrdXJ0b3Npc192MiA+PSAtIDEuNSAmIGt1cnRvc2lzX3YyIDw9IDEuNSAmCiAgICAgICAgICAgICAgICAgICAgICAgIHNrZXduZXNzX3YyID49IC0gMS41ICYgc2tld25lc3NfdjIgPD0gMS41LCAKICAgICAgICAgICAgICAgICAgICAgICJTaSIsICJObyIpCiAgKQpgYGAKCiMjIEZvcm1hdCB0aWR5IGRhdGEKCmBgYHtyfQpkZl93b3JrX3RpZHlfZXZhbHVhdGUgPC0gZGZfd29ya190aWR5X2V2YWx1YXRlICU+JQogIG11dGF0ZSgKICAgIFRpcG9fU2ltID0gZmN0X3JlY29kZShUaXBvX1NpbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIiA9ICJkYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTMiID0gImRhdGFfb3V0X20zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTYiID0gImRhdGFfb3V0X202IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTMgVjEiID0gImRhdGFfb3V0X20zdjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNMyBWMiIgPSAiZGF0YV9vdXRfbTN2MiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE0zIFYzIiA9ICJkYXRhX291dF9tM3YzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTYgVjEiID0gImRhdGFfb3V0X202djEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNNiBWMiIgPSAiZGF0YV9vdXRfbTZ2MiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IFYzIiA9ICJkYXRhX291dF9tNnYzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIEEiID0gImRhdGFfbm9ub3JtMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBCIiA9ICJkYXRhX25vbm9ybTIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJOby1NVk4gQyIgPSAiZGF0YV9ub25vcm0zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIEQiID0gImRhdGFfbm9ub3JtNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBFIiA9ICJkYXRhX25vbm9ybTUiKSwKICAgIFRpcG9fU2ltID0gZmN0X3JlbGV2ZWwoVGlwb19TaW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJNVk4iLCAiT0wgTTMiLCAiT0wgTTYiLCAiT0wgTTMgVjEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE0zIFYyIiwgIk9MIE0zIFYzIiwgIk9MIE02IFYxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IFYyIiwgIk9MIE02IFYzIikKICApICU+JSAKICBhcnJhbmdlKGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSkKYGBgCgojIyBEYXRhIGZvcm1hdCBmb3IgZXZhbHVhdGlvbgoKYGBge3J9CmRmX3dvcmtfdGlkeV9BIDwtIGRmX3dvcmtfdGlkeV9ldmFsdWF0ZSAlPiUgCiAgc2VsZWN0KGNvcnJlbGFjaW9uOlRpcG9fU2ltLCBOb3JtYWxfbXVsdGlfcjpub3JtX3VuaSkgJT4lCiAgcGl2b3RfbG9uZ2VyKAogICAgY29scyA9IE5vcm1hbF9tdWx0aV9yOm5vcm1fdW5pLAogICAgbmFtZXNfdG8gPSAiRXZhbHVhY2nDs24gTm9ybWFsaWRhZCIsCiAgICB2YWx1ZXNfdG8gPSAiRHgiCiAgKSAlPiUKICBtdXRhdGUoCiAgICBgRXZhbHVhY2nDs24gTm9ybWFsaWRhZGAgPSBpZmVsc2UoYEV2YWx1YWNpw7NuIE5vcm1hbGlkYWRgID09ICJOb3JtYWxfbXVsdGlfciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9ybWFsaWRhZCBtYXJkaWEiLCAiTm9ybWFsaWRhZCBBcyB5IEtzIikKICApCmBgYAoKIyMgUGxvdHMKCiMjIyBQbG90IE1hcmRpYQoKQ2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIG9mIGRhdGFmcmFtZXMgaWRlbnRpZmllZCBhcyBtdWx0aXZhcmlhdGUgbm9ybWFsIGluIGVhY2ggY29uZGl0aW9uLgoKYGBge3J9CmRmX3dvcmtfdGlkeV9BX21hcmRpYSA8LSBkZl93b3JrX3RpZHlfQSAlPiUgCiAgZmlsdGVyKGBFdmFsdWFjacOzbiBOb3JtYWxpZGFkYCA9PSAiTm9ybWFsaWRhZCBtYXJkaWEiKSAlPiUgCiAgY291bnQoY29ycmVsYWNpb24sIG4sIFRpcG9fU2ltLAogICAgICAgIER4LCBuYW1lID0gIkNhbnRpZGFkIikgJT4lIAogIGdyb3VwX2J5KGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSkgJT4lIAogIG11dGF0ZShQb3JjZW50YWplID0gQ2FudGlkYWQvc3VtKENhbnRpZGFkKSkgJT4lIAogIHNlbGVjdCgtQ2FudGlkYWQpICU+JSAKICBwaXZvdF93aWRlcigKICAgIG5hbWVzX2Zyb20gPSBEeCwKICAgIHZhbHVlc19mcm9tID0gUG9yY2VudGFqZSwKICAgIHZhbHVlc19maWxsID0gMAogICkgJT4lIAogIHVuZ3JvdXAoKQoKZGZfd29ya190aWR5X0FfbWFyZGlhCmBgYAoKUGxvdCBnZW5lcmF0aW9uOgoKYGBge3J9CnBsb3RfQV9tYXJkaWEgPC0gZGZfd29ya190aWR5X0FfbWFyZGlhICU+JSAKICBtdXRhdGUoY29ycmVsYWNpb24gPSBmYWN0b3IoY29ycmVsYWNpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAuMTIiLCAiMC4yMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjAuMzEiLCAiMC41MCIpKSwKICAgICAgICAgY29ycmVsYWNpb24gPSBmY3RfcmV2KGNvcnJlbGFjaW9uKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IFNpLCB5ID0gY29ycmVsYWNpb24sCiAgICAgICAgICAgICBhbHBoYSA9IGNvcnJlbGFjaW9uLCBsYWJlbCA9IHNjYWxlczo6cGVyY2VudChTaSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2N1cmFjeSA9IDEpKSkgKwogIGdlb21fY29sKCkgKwogIGZhY2V0X2dyaWQobiB+IFRpcG9fU2ltKSAgKwogIHNjYWxlX2FscGhhX2Rpc2NyZXRlKAogICAgbmFtZSA9ICJDb3JyZWxhY2nDs24iLAogICAgZ3VpZGUgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpCiAgKSArIAogIHNjYWxlX3hfY29udGludW91cygKICAgIGxpbWl0cyA9IGMoMCwgMSksCiAgICBicmVha3MgPSBjKDAsIDAuMjUsIDAuNTAsIDAuNzUsIDEpLAogICAgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpLAogICAgZXhwYW5kID0gYygwLCAwLjEpLAogICAgZ3VpZGUgPSBndWlkZV9heGlzKG4uZG9kZ2UgPSAyKQogICkgKwogIGdlb21fbGFiZWwoCiAgICBzaXplID0gMy41LAogICAgbGFiZWwuc2l6ZSA9IDAuMjUsIAogICAgbGFiZWwuciA9IHVuaXQoMC4xNSwgImxpbmVzIiksCiAgICBsYWJlbC5wYWRkaW5nID0gdW5pdCgwLjE1LCAibGluZXMiKSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLAogICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwogIGxhYnMoCiAgICB5ID0gIiIsCiAgICB4ID0gIiIKICApICsgCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IDExLAogICAgICBmYWNlPSJib2xkIiksIAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEsCiAgICAgIGZhY2U9InBsYWluIiwKICAgICAgY29sb3VyPSJibGFjayIpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gMTEsCiAgICAgIGZhY2UgPSAiYm9sZCIKICAgICksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgZmFjZT0icGxhaW4iLAogICAgICBjb2xvdXI9ImJsYWNrIiwKICAgICAgc2l6ZT0xMSksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICBmYWNlPSJwbGFpbiIsCiAgICAgIGNvbG91cj0iYmxhY2siLAogICAgICBzaXplPTExKSwKICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNiwgImxpbmVzIikKICApIApgYGAKCiFbXShpbWcvUGxvdF9tYXJkaWFfY29tcGxldGVfc2FtcGxlLnBuZykKCgojIyMgUGxvdCBTa2V3bmVzcyBhbmQgS3VydG9zaXMKCkNhbGN1bGF0ZSB0aGUgcGVyY2VudGFnZSBvZiBkYXRhZnJhbWVzIGlkZW50aWZpZWQgYXMgdW5pdmFyaWF0ZSBub3JtYWxpdHkgaW4gZWFjaCBjb25kaXRpb24uCgpgYGB7cn0KZGZfd29ya190aWR5X0FfYXNfa3MgPC0gZGZfd29ya190aWR5X0EgJT4lIAogIGZpbHRlcihgRXZhbHVhY2nDs24gTm9ybWFsaWRhZGAgPT0gIk5vcm1hbGlkYWQgQXMgeSBLcyIpICU+JSAKICBjb3VudChjb3JyZWxhY2lvbiwgbiwgVGlwb19TaW0sCiAgICAgICAgRHgsIG5hbWUgPSAiQ2FudGlkYWQiKSAlPiUgCiAgZ3JvdXBfYnkoY29ycmVsYWNpb24sIG4sIFRpcG9fU2ltKSAlPiUgCiAgbXV0YXRlKFBvcmNlbnRhamUgPSBDYW50aWRhZC9zdW0oQ2FudGlkYWQpKSAlPiUgCiAgc2VsZWN0KC1DYW50aWRhZCkgJT4lIAogIHBpdm90X3dpZGVyKAogICAgbmFtZXNfZnJvbSA9IER4LAogICAgdmFsdWVzX2Zyb20gPSBQb3JjZW50YWplLAogICAgdmFsdWVzX2ZpbGwgPSAwCiAgKSAlPiUgCiAgdW5ncm91cCgpCmBgYAoKUGxvdCBnZW5lcmF0aW9uOgoKYGBge3J9CnBsb3RfQV9hc19rcyA8LSBkZl93b3JrX3RpZHlfQV9hc19rcyAlPiUgCiAgbXV0YXRlKGNvcnJlbGFjaW9uID0gZmFjdG9yKGNvcnJlbGFjaW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwLjEyIiwgIjAuMjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIwLjMxIiwgIjAuNTAiKSksCiAgICAgICAgIGNvcnJlbGFjaW9uID0gZmN0X3Jldihjb3JyZWxhY2lvbikpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBTaSwgeSA9IGNvcnJlbGFjaW9uLAogICAgICAgICAgICAgYWxwaGEgPSBjb3JyZWxhY2lvbiwgbGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQoU2ksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNjdXJhY3kgPSAxKSkpICsKICBnZW9tX2NvbCgpICsKICBmYWNldF9ncmlkKG4gfiBUaXBvX1NpbSkgICsKICBzY2FsZV9hbHBoYV9kaXNjcmV0ZSgKICAgIG5hbWUgPSAiQ29ycmVsYWNpw7NuIiwKICAgIGd1aWRlID0gZ3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUUlVFKQogICkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICBsaW1pdHMgPSBjKDAsIDEpLAogICAgYnJlYWtzID0gYygwLCAwLjI1LCAwLjUwLCAwLjc1LCAxKSwKICAgIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoKSwKICAgIGV4cGFuZCA9IGMoMCwgMC4xKSwKICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhuLmRvZGdlID0gMikKICApICsKICBnZW9tX2xhYmVsKAogICAgc2l6ZSA9IDMuNSwKICAgIGxhYmVsLnNpemUgPSAwLjI1LCAKICAgIGxhYmVsLnIgPSB1bml0KDAuMTUsICJsaW5lcyIpLAogICAgbGFiZWwucGFkZGluZyA9IHVuaXQoMC4xNSwgImxpbmVzIiksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwKICAgIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBsYWJzKAogICAgeSA9ICIiLAogICAgeCA9ICIiCiAgKSArIAogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgIHRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIHNpemUgPSAxMSwKICAgICAgZmFjZT0iYm9sZCIpLCAKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IDExLAogICAgICBmYWNlPSJwbGFpbiIsCiAgICAgIGNvbG91cj0iYmxhY2siKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgc2l6ZSA9IDExLAogICAgICBmYWNlID0gImJvbGQiCiAgICApLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoCiAgICAgIGZhY2U9InBsYWluIiwKICAgICAgY29sb3VyPSJibGFjayIsCiAgICAgIHNpemU9MTEpLAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgIC